//
//  CrazySocketUtility.m
//  test
//
//  Created by 马军凯 on 2019/1/10.
//  Copyright © 2019年 ZH. All rights reserved.
//

#import "CrazySocketUtility.h"
#import "Reachability.h" //网络监听
#import "CrazyChatViewController.h" //客服聊天页面
#import "CrazyChatCustomListViewController.h" //客服列表
#import <UserNotifications/UserNotifications.h> //通知

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block)\
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
    block();\
} else {\
    dispatch_async(dispatch_get_main_queue(), block);\
}
#endif

@interface CrazySocketUtility () <SRWebSocketDelegate>

@property (nonatomic, strong) NSTimer *heartBeatTimer; //心跳定时器
@property (nonatomic, strong) NSTimer *netWorkTestingTimer; //没有网络的时候检测网络的定时器
@property (nonatomic, strong) dispatch_queue_t queue; //数据请求队列(串行队列)
@property (nonatomic, assign) NSTimeInterval reConnectTime; //重连时间
@property (nonatomic, strong) NSMutableArray *sendDataArray; //存储要发送给服务器端的数据
@property (nonatomic, assign) BOOL isActivelyClose; //用于判断是否主动关闭长链接 如果是主动断开连接，连接失败的代理中，就不用执行 重新连接方法
@property (nonatomic, strong) Reachability *conn; //网络情况
@property (nonatomic, copy) NSString *platForm_id; //平台ID
@property (nonatomic, copy) NSString *user_id; //user_id

@end

@implementation CrazySocketUtility

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

//初始化
+ (instancetype)sharedSocketManager {
    static CrazySocketUtility *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (instancetype)init {
    if (self = [super init]) {
        self.reConnectTime = 0;
        self.isActivelyClose = NO;
        self.queue = dispatch_queue_create("BF", NULL);
        self.sendDataArray = [[NSMutableArray alloc] init];
        //网络监听
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkConnectChangeState:) name:kReachabilityChangedNotification object:nil];
        self.conn = [Reachability reachabilityForInternetConnection];
        [self.conn startNotifier];
    }
    return self;
}

#pragma mark 建立长链接
- (void)connectServerWithUser_id:(NSString *)user_id platID:(NSString *)platID {
    if (self.socket) {
        self.socket = nil;
    }
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:SOCKET_URL]];
    self.socket = [[SRWebSocket alloc] initWithURLRequest:request];
    self.socket.delegate = self;
    [self.socket open];
    
    if (user_id == nil) {
        return;
    }
    NSString *platFormID = @"";
    if (platID == nil || [platID isEqualToString:@""]) {
        platFormID = @"1";
    } else {
        platFormID = platID;
    }
    
    self.user_id = user_id;
    self.platForm_id = platFormID;
}

#pragma mark 重连服务器
- (void)reConnetServer {
    if (self.socket.readyState == SR_OPEN) {
        return;
    }
    if (self.reConnectTime > 20) {
        self.reConnectTime = 0;
        return;
    }
    
    CrazyWeakSelf;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (weakSelf.socket.readyState == SR_OPEN || weakSelf.socket.readyState == SR_CONNECTING) {
            return ;
        }
        [weakSelf connectServerWithUser_id:weakSelf.user_id platID:weakSelf.platForm_id];
        NSLog(@"正在重连。。。。。。");
        weakSelf.reConnectTime = weakSelf.reConnectTime + 2;
    });
}

#pragma mark 关闭长链接
- (void)SRWebSocketClose {
    self.isActivelyClose = YES;
    [self webSocketClose];
    //关闭心跳
    [self destoryHeartBeat];
    //关闭网络
    [self destoryNetWorkStartTesting];
    
}
//关闭
- (void)webSocketClose {
    if (self.socket){
        [self.socket close];
        self.socket = nil;
    }
}

#pragma mark 发送数据给服务器
- (void)sendDataToServer:(id)data {
    NSDictionary *params = data;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    [self.sendDataArray addObject:jsonString];
    [self sendeDataToServer];
}
//发送
- (void)sendeDataToServer {
    CrazyWeakSelf;
    //把数据放到一个队列中
    dispatch_async(self.queue, ^{
        if ([Reachability reachabilityForInternetConnection] == NotReachable) {
            //开启网络检测定时器
            [weakSelf noNetWorkStartTestingTimer];
        } else {
            if (weakSelf.socket != nil) {
                if (weakSelf.socket.readyState == SR_OPEN) {
                    if (weakSelf.sendDataArray.count > 0) {
                        NSString *data = [weakSelf.sendDataArray lastObject];
                        [weakSelf.socket send:data];
                        [weakSelf.sendDataArray removeObjectAtIndex:weakSelf.sendDataArray.count - 1];
                        if (weakSelf.sendDataArray.count > 0) {
                            [weakSelf sendeDataToServer];
                        }
                    }
                } else if (weakSelf.socket.readyState == SR_CONNECTING) {
                    NSLog(@"正在重连中");
                    [weakSelf reConnetServer];
                } else if (weakSelf.socket.readyState == SR_CLOSED || weakSelf.socket.readyState == SR_CLOSING) {
                    [weakSelf reConnetServer];
                }
            } else {
                [weakSelf connectServerWithUser_id:weakSelf.user_id platID:weakSelf.platForm_id];
            }
        }
    });
}



#pragma mark 定时检测网络
- (void)noNetWorkStartTesting {
    if ([Reachability reachabilityForInternetConnection] != NotReachable) {
        //关闭网络检测器
        [self destoryNetWorkStartTesting];
        //开始重连
        [self reConnetServer];
    }
}

#pragma mark 初始化心跳
- (void)initHeartBeat {
    if (self.heartBeatTimer) {
        return;
    }
    
    [self destoryHeartBeat];
    
    CrazyWeakSelf;
    dispatch_main_async_safe(^{
        weakSelf.heartBeatTimer = [NSTimer timerWithTimeInterval:10 target:weakSelf selector:@selector(senderHeartBeat) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:weakSelf.heartBeatTimer forMode:NSRunLoopCommonModes];
    })
}
//发送心跳
- (void)senderHeartBeat {
    CrazyWeakSelf;
    dispatch_main_async_safe(^{
        if (weakSelf.socket.readyState == SR_OPEN) {
            NSDictionary *params = @{@"TYPE" : @"HEART"};
            NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params options:0 error:nil];
            //            NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
            [weakSelf.socket sendPing:jsonData];
        }
    })
}

#pragma mark 销毁心跳
- (void)destoryHeartBeat {
    CrazyWeakSelf;
    dispatch_main_async_safe(^{
        if (weakSelf.heartBeatTimer) {
            if ([weakSelf.heartBeatTimer respondsToSelector:@selector(isValid)]) {
                if ([weakSelf.heartBeatTimer isValid]) {
                    [weakSelf.heartBeatTimer invalidate];
                    weakSelf.heartBeatTimer = nil;
                }
            }
        }
    })
}

#pragma mark 网络检测
- (void)noNetWorkStartTestingTimer {
    CrazyWeakSelf;
    dispatch_main_async_safe(^{
        weakSelf.netWorkTestingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(noNetWorkStartTesting) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:weakSelf.netWorkTestingTimer forMode:NSDefaultRunLoopMode];
    })
}
//检测网络
- (void)destoryNetWorkStartTesting {
    CrazyWeakSelf
    dispatch_main_async_safe(^{
        if (weakSelf.netWorkTestingTimer) {
            if ([weakSelf.netWorkTestingTimer respondsToSelector:@selector(isValid)]) {
                [weakSelf.netWorkTestingTimer invalidate];
                weakSelf.netWorkTestingTimer = nil;
            }
        }
    })
}


#pragma mark 退出登录
- (void)logoutWebSocket {
    NSDictionary *params = @{@"TYPE" : @"LOGOUT",
                             @"DATA" : @{@"USER_TYPE" : @"USER"}
                             };
//    [self sendDataToServer:params];
    [self SRWebSocketClose];
}

#pragma mark 代理
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    NSLog(@"打开成功");
    //    [self initHeartBeat];//初始化心跳
//    if ([self.sendDataArray count] > 0) {
//        [self sendeDataToServer];
//    }
}
//连接失败
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    if (self.isActivelyClose) {
        return;
    }
    
    [self destoryHeartBeat]; //销毁心跳
    if ([Reachability reachabilityForInternetConnection] == NotReachable) {
        [self noNetWorkStartTestingTimer];
    } else {
        [self reConnetServer];
    }
}

- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
    if (self.socket.readyState == SR_OPEN || self.isActivelyClose) {
        return;
    }
    
    [self destoryHeartBeat];
    
    if ([Reachability reachabilityForInternetConnection] == NotReachable) {
        [self noNetWorkStartTestingTimer];
    } else {
        [self reConnectTime];
    }
}

//接收服务器发送的pong消息
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongData {
    NSLog(@"心跳回执%@", pongData);
}

- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    NSLog(@"返回数据:%@", message);
    NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:messageData options:NSJSONReadingMutableContainers error:nil];
    if ([json[@"TYPE"] isEqualToString:@"SUCCESS"]) {
        //连接成功
        NSDictionary *dataDict = json[@"DATA"];
        if ([dataDict[@"TYPE"] isEqualToString:@"CONNECTED"]) {
            NSLog(@"连接成功");
            if (self.user_id == nil) {
                return;
            }
            NSDictionary *params = @{@"TYPE" : @"LOGIN",
                                     @"DATA" : @{@"USER_TYPE" : @"USER",
                                                 @"MEMBER_ID" : self.user_id,
                                                 @"PLATFORM_ID" : self.platForm_id
                                                 }
                                     };
            [self sendDataToServer:params];
        } else if ([dataDict[@"TYPE"] isEqualToString:@"LOGIN"]) {
            NSLog(@"登录成功");
        } else if ([dataDict[@"TYPE"] isEqualToString:@"MESSAGE_DELIVERD_SERVER"]) {
            NSLog(@"后台接收到了");
            [[NSNotificationCenter defaultCenter] postNotificationName:@"CrazyChatDeliverdMessageData" object:nil userInfo:@{@"MESSAGE_ID": dataDict[@"MESSAGE_ID"]}];
        } else if ([dataDict[@"TYPE"] isEqualToString:@"MATCH_CUSTOMER"]) {
            NSLog(@"预聊天消息");
            NSDictionary *userInfo = @{@"MESSAGE_ID" : @"",
                                       @"MESSAGE_TYPE" : @"TEXT",
                                       @"MESSAGE_DATA" : [NSString stringWithFormat:@"%@", dataDict[@"MESSAGE"]],
                                       @"FORM_TYPE" : @"CUSTOMER"};
            [[NSNotificationCenter defaultCenter] postNotificationName:@"CrazyChatBackMessageData" object:nil userInfo:userInfo];
        }
    } else if ([json[@"TYPE"] isEqualToString:@"WARNING"]) {
        NSDictionary *dict = json[@"DATA"];
        NSLog(@"%@", dict[@"MESSAGE"]);
        [UIAlertController alertViewWith:dict[@"MESSAGE"]];
    } else if ([json[@"TYPE"] isEqualToString:@"ERROR"]) {
        NSDictionary *dict = json[@"DATA"];
        NSLog(@"%@", dict[@"MESSAGE"]);
        [UIAlertController alertViewWith:dict[@"MESSAGE"]];
    } else if ([json[@"TYPE"] isEqualToString:@"MESSAGE"]) {
        NSLog(@"后台发送的数据");
        NSDictionary *dataDict = json[@"DATA"];
        NSString *messageID = [NSString stringWithFormat:@"%@", dataDict[@"MESSAGE_ID"]];
        NSString *messageType = [NSString stringWithFormat:@"%@", dataDict[@"MESSAGE_TYPE"]];
        NSString *messageData = [NSString stringWithFormat:@"%@", dataDict[@"MESSAGE_DATA"]];
        NSString *fromID = [NSString stringWithFormat:@"%@", dataDict[@"FROM_ID"]];
        NSDictionary *userInfo = @{@"MESSAGE_ID" : messageID,
                                   @"MESSAGE_TYPE" : messageType,
                                   @"MESSAGE_DATA" : messageData,
                                   @"FROM_ID" : fromID,
                                   @"FORM_TYPE" : @"CUSTOMER"};
        //获取当前控制器
        UIViewController *currentVC = [self getCurrentVC];
        //判断当前在哪个页面
        if ([currentVC isKindOfClass:[CrazyChatViewController class]]) {
            CrazyChatViewController *vc = (CrazyChatViewController *)currentVC;
            if ([vc.store_id isEqualToString:fromID]) {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"CrazyChatBackMessageData" object:nil userInfo:userInfo];
            } else {
                [[NSNotificationCenter defaultCenter] postNotificationName:@"CrazyChatListBackMessageData" object:nil userInfo:userInfo];
            }
        } else if ([currentVC isKindOfClass:[CrazyChatCustomListViewController class]]) {
            [[NSNotificationCenter defaultCenter] postNotificationName:@"CrazyChatListBackMessageData" object:nil userInfo:userInfo];
        } else {
            //标题
            NSString *messageTitle = [NSString stringWithFormat:@"%@%@", @"客服", fromID];
            //消息副标题
            NSString *messageSubTitle = messageData;
            if ([messageType isEqualToString:@"TEXT"]) {
//                messageSubTitle = messageData;
//            } else if ([messageType isEqualToString:@"IMAGE"]) {
//                messageSubTitle = messageData;
//            } else if ([messageType isEqualToString:@"VOICE"]) {
//                messageSubTitle = @"语音";
//            } else if ([messageType isEqualToString:@"ORDER"]) {
//                messageSubTitle = @"订单信息";
//            } else if ([messageType isEqualToString:@"GOODS"]) {
//                messageSubTitle = @"商品信息";
//            } else {
//                messageSubTitle = @"";
            }
            UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
            UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
            content.title = [NSString localizedUserNotificationStringForKey:messageTitle arguments:nil];
            content.body = [NSString localizedUserNotificationStringForKey:messageSubTitle arguments:nil];
            content.sound = [UNNotificationSound defaultSound];
            content.userInfo = userInfo;
            
            UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.5 repeats:NO];
            UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"CrazyChatWebSocketNotification" content:content trigger:trigger];
            [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
                
            }];
            
            //保存数据
            NSInteger noReadCount = [[NSUserDefaults standardUserDefaults] integerForKey:fromID];
            NSInteger allNoReadCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"CrazyChatAllNoReadMessageCount"];
            [[NSUserDefaults standardUserDefaults] setInteger:noReadCount + 1 forKey:fromID];
            [[NSUserDefaults standardUserDefaults] setInteger:allNoReadCount + 1 forKey:@"CrazyChatAllNoReadMessageCount"];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
    }
}

#pragma mark 当前网络连接情况
- (void)checkConnectChangeState:(NSNotification *)sender {
    Reachability *connnnn = [sender object];
//    Reachability *connnnn = [Reachability reachabilityForInternetConnection];
    [self noNetWorkStartTestingTimer];
    if ([connnnn isKindOfClass:[Reachability class]]) {
        NetworkStatus status = [connnnn currentReachabilityStatus];
        switch (status) {
            case NotReachable:
                NSLog(@"notReachable");
                [self SRWebSocketClose];
                break;
            case ReachableViaWiFi:
                NSLog(@"wifi");
                [self connectServerWithUser_id:self.user_id platID:self.platForm_id];
                break;
            case ReachableViaWWAN:
                NSLog(@"wan");
                [self connectServerWithUser_id:self.user_id platID:self.platForm_id];
                break;
            default:
                NSLog(@"不知道状态");
                break;
        }
    }
}

//获取当前屏幕显示的viewcontroller
- (UIViewController *)getCurrentVC {
    
    UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
    UIViewController *currentVC = window.rootViewController;
    BOOL runLoopFind = YES;
    
    while (runLoopFind) {
        if (currentVC.presentedViewController) {
            currentVC = currentVC.presentedViewController;
        } else if ([currentVC isKindOfClass:[UINavigationController class]]) {
            UINavigationController *naVC = (UINavigationController *)currentVC;
            currentVC = [naVC.childViewControllers lastObject];
        } else if ([currentVC isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tabBarVC = (UITabBarController *)currentVC;
            currentVC = tabBarVC.selectedViewController;
        } else {
            NSUInteger childVCCount = currentVC.childViewControllers.count;
            if (childVCCount > 0) {
                currentVC = currentVC.childViewControllers.lastObject;
                return currentVC;
            } else {
                return currentVC;
            }
        }
    }
    return currentVC;
}

@end























